﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using Felbot.Interaction;

namespace Felbot {
    /// <summary>This class represents the user entry manager form, where the user can add, edit, or remove user entries.</summary>
    public partial class frmUserEntryManager : Form {
        private XmlEntry m_Current;
        private List<string> m_Flags;
        private List<string> m_Groups;
        private string m_OldLabel;
        private bool m_EntrySaved = true;

        /// <summary>
        /// Create a new user entry manager form.
        /// </summary>
        public frmUserEntryManager() {
            InitializeComponent();
        }

        private void frmUserEntryManager_Load(object sender, EventArgs e) {
            LoadEntryList();
        }

        private void LoadEntryList() {
            foreach (XmlEntry entry in UserEntryControl.EntryList)
                lvEntries.Items.Add(new ListViewItem(new string[] { entry.Name, entry.EntryType.ToString() }));
        }

        private void lvEntries_SelectedIndexChanged(object sender, EventArgs e) {
            if (m_Current != null && !m_EntrySaved) {
                if (MessageBox.Show("The current entry is not saved.\r\n" +
                                    "Do you want to save changes?",
                                    "Felbot",
                                    MessageBoxButtons.YesNo,
                                    MessageBoxIcon.Question,
                                    MessageBoxDefaultButton.Button1)
                        == DialogResult.Yes) {
                    SaveCurrentEntry();
                }
            }
            if (lvEntries.SelectedItems.Count == 1) {
                LoadEntry(lvEntries.SelectedItems[0].Text);
                pnlEntryEdit.Show();
                btnEntrySave.Show();
                btnEntryCancel.Show();
                lblInfo.Text = "Edit entry " + m_Current.Name + ".";
            } else {
                m_Current = null;
                pnlEntryEdit.Hide();
                btnEntrySave.Hide();
                btnEntryCancel.Hide();
                lblInfo.Text = "Select a user entry to edit.";
            }
            btnEntryRemove.Enabled = (lvEntries.Items.Count > 0);
        }

        private void lvEntries_BeforeLabelEdit(object sender, LabelEditEventArgs e) {
            btnEntryRemove.Enabled = false;
            btnEntryAdd.Enabled = false;
            m_OldLabel = lvEntries.Items[e.Item].Text;
            pnlEntryEdit.Hide();
            btnEntrySave.Hide();
            btnEntryCancel.Hide();
            lblInfo.Text = "Edit entry name for " + m_OldLabel + ".";
        }

        private void lvEntries_AfterLabelEdit(object sender, LabelEditEventArgs e) {
            lvEntries.SelectedItems.Clear();
            btnEntryAdd.Enabled = true;
            lvEntries.Items[e.Item].Selected = true;
            if (e.Label == null)
                return;
            UserEntryControl.GetEntry(m_OldLabel).Name = e.Label;
            LoadEntry(lvEntries.SelectedItems[0].Text);
            lblInfo.Text = "Edit entry " + m_Current.Name + ".";
        }

        private void LoadEntry(string name) {
            foreach (XmlEntry entry in UserEntryControl.EntryList)
                if (entry.Name == name)
                    LoadEntry(entry);
        }

        private void LoadEntry(XmlEntry entry) {
            m_Current = entry;

            txtEntryName.Text = entry.Name;
            switch (entry.EntryType) {
                case XmlEntryType.Group: cboEntryType.SelectedIndex = 0; break;
                default:
                case XmlEntryType.User: cboEntryType.SelectedIndex = 1; break;
                case XmlEntryType.Client: cboEntryType.SelectedIndex = 2; break;
                case XmlEntryType.Phrase: cboEntryType.SelectedIndex = 3; break;
                case XmlEntryType.GameStat: cboEntryType.SelectedIndex = 4; break;
                case XmlEntryType.Wc3Clan: cboEntryType.SelectedIndex = 5; break;
                case XmlEntryType.Wc3ClanRank: cboEntryType.SelectedIndex = 6; break;
            }
            m_Flags = entry.Has.Flags;
            txtEntryFlags.Text = GetStringFromList(m_Flags);
            m_Groups = UserEntryControl.GetGroupsContaining(entry);
            txtEntryGroups.Text = GetStringFromList(m_Groups);
            foreach (string note in entry.Notes)
                if (!note.StartsWith("s:::")) //hide script notes
                    lvEntryNotes.Items.Add(note);
            lblCreated.Text = "Created on " + entry.Created.Time.ToLongDateString() + " by " + entry.Created.By;
            if (entry.Edits.Count > 0) {
                XmlEntryEdit edit = entry.Edits[entry.Edits.Count - 1];
                lblEdited.Text = "Last edited on " + edit.Time.ToLongDateString() + " by " + entry.Created.By;
            } else {
                lblEdited.Text = "Never edited";
            }
        }

        private void SaveCurrentEntry() {
            switch (cboEntryType.SelectedIndex) {
                case 0: m_Current.EntryType = XmlEntryType.Group; break;
                default:
                case 1: m_Current.EntryType = XmlEntryType.User; break;
                case 2: m_Current.EntryType = XmlEntryType.Client; break;
                case 3: m_Current.EntryType = XmlEntryType.Phrase; break;
                case 4: m_Current.EntryType = XmlEntryType.GameStat; break;
                case 5: m_Current.EntryType = XmlEntryType.Wc3Clan; break;
                case 6: m_Current.EntryType = XmlEntryType.Wc3ClanRank; break;
            }
            m_Current.Has.Flags = m_Flags;
            UserEntryControl.SetGroupsContaining(m_Current, m_Groups);
            m_Current.Notes.Clear();
            foreach (ListViewItem item in lvEntryNotes.Items)
                m_Current.Notes.Add(item.Text);
            UserEntryControl.SetEditNow(m_Current, "User Entry Manager", DateTime.Now);

            //is name changed?
            if (txtEntryName.Text != m_Current.Name) {
                //yes? change the list then the entry object
                foreach (ListViewItem item in lvEntries.Items) {
                    if (item.Text == m_Current.Name) {
                        //change entry name in list
                        item.Text = txtEntryName.Text;
                    }
                }
                //change all <member> references
                UserEntryControl.UpdateName(m_Current.Name, txtEntryName.Text);
                //change emtry name
                m_Current.Name = txtEntryName.Text;
            }

            UserEntryControl.Save();
        }

        private string GetStringFromList(List<string> list) {
            string l = "";
            foreach (string ll in list)
                l += ll + ", ";
            if (l != "")
                l = l.Substring(0, l.Length - 2);
            return l;
        }

        private void NewEntry() {
            string name = UserEntryControl.GetMakeName;
            XmlEntry entry = UserEntryControl.MakeEntry(name);
            ListViewItem item = lvEntries.Items.Add(new ListViewItem(new string[] { entry.Name, entry.EntryType.ToString() }));
            item.Selected = true;
        }

        private void btnEntryAdd_Click(object sender, EventArgs e) {
            NewEntry();
        }

        private void btnEntryRemove_Click(object sender, EventArgs e) {
            foreach (ListViewItem item in lvEntries.SelectedItems) {
                UserEntryControl.RemoveEntry(UserEntryControl.GetEntry(item.Text));
                item.Remove();
            }
            btnEntryRemove.Enabled = false;
        }

        private void btnEntrySave_Click(object sender, EventArgs e) {
            SaveCurrentEntry();
            lvEntries.SelectedItems.Clear();
        }

        private void btnEntryCancel_Click(object sender, EventArgs e) {
            m_EntrySaved = true;
            lvEntries.SelectedItems.Clear();
        }

        private void btnOK_Click(object sender, EventArgs e) {
            SaveCurrentEntry();
            lvEntries.SelectedItems.Clear();
            this.Close();
        }

        private void btnCancel_Click(object sender, EventArgs e) {
            m_EntrySaved = true;
            lvEntries.SelectedItems.Clear();
            this.Close();
        }

        private void control_Enter(object sender, EventArgs e) {
            lblInfo.Text = tip.GetToolTip((Control) sender);
        }

        private void control_Changed(object sender, EventArgs e) {
            m_EntrySaved = false;
            btnEntrySave.Enabled = true;
        }

        private void cboEntryType_SelectedIndexChanged(object sender, EventArgs e) {
            control_Changed(sender, e);
            switch (cboEntryType.SelectedIndex) {
                case 0:
                    lblEntryTypeDesc.Text =
                        "Group:  This entry can contain other entries and its name does not refer to a specific user.\r\n" +
                        "To add an entry to a group, go to the entry and set a check next to it in the group manager (\"...\" button next to groups box).";
                    break;
                default:
                case 1:
                    lblEntryTypeDesc.Text =
                        "User:  This entry refers to a specific user or group of users who match the name of the entry.\r\n" +
                        "The name of the entry can have wildcards (*s) (example: fel.* = anyone whose name starts with \"fel.\") or regular expressions if prefixed with \"reg::\" (examples: reg::. = all users, reg::?tag?name = any user with the tag enclosed in any character, reg::fel\\.(bot|user) = \"fel.bot\" or \"fel.user\").";
                    break;
                case 2:
                    lblEntryTypeDesc.Text =
                        "Client:  This entry refers to any user who is on the specified client.\r\n" +
                        "Valid client names are: \"SC\", \"D1\", \"D2\", \"WC2\", \"WC3\", and any four-character client IDs.";
                    break;
                case 3:
                    lblEntryTypeDesc.Text =
                        "Phrase:  This entry refers to any user who has just said the specified phrase.\r\n" +
                        "As may be quickly appearent, many flags do not affect Phrase entries. Only special action-based flags such as BAN, NOBAN (overrides BAN from groups containing this entry) etc affect this.";
                    break;
                case 4:
                    lblEntryTypeDesc.Text =
                        "Game Stat:  This entry refers to any user who has the stats specified.\r\n" +
                        "This complex entry type has the following format: client::stat=value&stat=value where client can be \"SC\", \"D1\", \"D2\", \"WC2\", \"WC3\", and stat see readme.";
                    break;
                case 5:
                    lblEntryTypeDesc.Text =
                        "Wc3 Clan:  This entry refers to any user who has the specified WC3 clan tag.";
                    break;
                case 6:
                    lblEntryTypeDesc.Text =
                        "WC3 Clan Rank:  This entry refers to any user in the bot's clan with the specified clan rank (init, peon, grunt, sham, chief).";
                    break;
            }
        }

        private void btnEntryFlags_Click(object sender, EventArgs e) {
            new frmFlagsManager(this, m_Current).ShowDialog(this);
        }

        public void SetFlags(List<string> flags) {
            m_Flags = flags;
            txtEntryFlags.Text = GetStringFromList(m_Flags);
        }

        private void btnEntryGroups_Click(object sender, EventArgs e) {
            new frmGroupsSelector(this, m_Current).ShowDialog(this);
        }

        internal void SetGroups(List<string> groups) {
            m_Groups = groups;
            txtEntryGroups.Text = GetStringFromList(m_Groups);
        }

        private void btnEntryNotesAdd_Click(object sender, EventArgs e) {
            ListViewItem item = lvEntryNotes.Items.Add(new ListViewItem(""));
            item.BeginEdit();
        }

        private void btnEntryNotesRemove_Click(object sender, EventArgs e) {
            foreach (ListViewItem item in lvEntryNotes.SelectedItems)
                item.Remove();
        }

        private void lvEntryNotes_SelectedIndexChanged(object sender, EventArgs e) {
            btnEntryNotesRemove.Enabled = (lvEntryNotes.SelectedItems.Count > 0);
        }

        private void lvEntryNotes_BeforeLabelEdit(object sender, LabelEditEventArgs e) {
            btnEntryNotesRemove.Enabled = false;
            btnEntryNotesAdd.Enabled = false;
            m_OldLabel = lvEntryNotes.Items[e.Item].Text;
            lblInfo.Text = "Edit note.";
        }

        private void lvEntryNotes_AfterLabelEdit(object sender, LabelEditEventArgs e) {
            lvEntryNotes.SelectedItems.Clear();
            btnEntryNotesAdd.Enabled = true;
            lvEntryNotes.Items[e.Item].Selected = true;
            if (e.Label == null)
                return;
            lblInfo.Text = "Add, edit, or remove notes.";
        }

        private void btnViewEdits_Click(object sender, EventArgs e) {
            new frmEditViewer(this, m_Current).ShowDialog(this);
        }
    }
}
